#ifndef TCP_CONNECTION_H_
#define TCP_CONNECTION_H_

#include <memory>
#include <string>

#include "netlib/base/noncopyable.h"
#include "netlib/net/call_backs.h"
#include "netlib/net/event/channel.h"
#include "netlib/net/socket/buffer.h"
#include "netlib/net/socket/inet_address.h"
#include "netlib/net/socket/socket.h"

namespace netlib::net {

class TcpConnection : public NonCopyable,
                      public std::enable_shared_from_this<TcpConnection> {
public:
	TcpConnection(EventLoop* loop,
	              int fd,
	              const InetAddress& local,
	              const InetAddress& peer,
	              std::string name);
	~TcpConnection();

	void SetConnectionCallback(const ConnectionCallback& cb) { conn_cb_ = cb; }
	void SetMessageCallback(const MessageCallback& cb) { msg_cb_ = cb; }
	void SetCloseCallback(const CloseCallback& cb) { close_cb_ = cb; }
	void SetWriteCompleteCallback(const WriteCompleteCallback& cb) { write_complete_cb_ = cb; }
	EventLoop* GetEventLoop() const { return loop_; }
	std::string Name() const { return name_; }
	bool Connected() const { return state_ == kConnected; }
	const InetAddress& LocalAddress() const { return kLocalAddr; }
	const InetAddress& PeerAddress() const { return kPeerAddr; }
	const char* StateToString() const;

	void Established();
	// void connectEstablished();
	void Send(const std::string& msg);
	void Send(const Buffer& buf) { Send(buf.PeekString(buf.ReadableBytes())); }
	void Shutdown();
	void Destroyed();

private:
	void HandleRead(Timestamp time);
	void HandleClose();
	void HandleWrite();
	void HandleError();
	void SendInLoop(const std::string& msg);
	void ShutdownInLoop();

	enum StateE { kInit, kConnecting, kConnected, kDisconnected, kDisconnecting };

	EventLoop* loop_;
	StateE state_{kConnecting};
	std::string name_;
	const Socket kSocket;
	const InetAddress kLocalAddr;
	const InetAddress kPeerAddr;
	Channel channel_;
	ConnectionCallback conn_cb_;
	MessageCallback msg_cb_;
	CloseCallback close_cb_;
	WriteCompleteCallback write_complete_cb_;
	Buffer input_buffer_;  // 读取数据
	Buffer output_buffer_; // 发送数据
};

using TcpConnectionPtr = std::shared_ptr<TcpConnection>;

} // namespace netlib::net

#endif // TCP_CONNECTION_H_